package multicastqosrouting;

import java.util.ArrayList;

/**
 *
 * @author yeison
 */
public class RoutingGeneticAlgorithm {

    /*
     * Constructor
     */
    public RoutingGeneticAlgorithm(int numberOfIndivuals, double mutationRate, int numbeOfGenerations) {
        i_numberOfIndividuals = numberOfIndivuals;
        i_mutationRate = mutationRate;
        i_numberOfGenerations = numbeOfGenerations;
    }

    public RoutingGeneticAlgorithm(int numberOfIndivuals, double mutationRate, int numbeOfGenerations, int numberOfParents) {
        i_numberOfIndividuals = numberOfIndivuals;
        i_mutationRate = mutationRate;
        i_numberOfGenerations = numbeOfGenerations;
        i_numberOfSelectedParents = numberOfParents;
    }

    /*
     * Getters
     */
    public ArrayList<Double> getAverageFitness() {
        return averageFitness;
    }

    public ArrayList<Double> getMinFitness() {
        return minFitness;
    }

    public double getMutationRate() {
        return i_mutationRate;
    }

    public int getNumberOfGenerations() {
        return i_numberOfGenerations;
    }

    public int getNumberOfIndividuals() {
        return i_numberOfIndividuals;
    }

    public int getNumberOfSelectedParents() {
        return i_numberOfSelectedParents;
    }

    public String getLowerCostPath() {
        for (int j = 0; j < lowerCostPath.get(lowerCostPath.size() - 1).size(); j++) {
            System.out.print(lowerCostPath.get(lowerCostPath.size() - 1).get(j) + " ");
            lowerCostPathFound += lowerCostPath.get(lowerCostPath.size() - 1).get(j) + " ";
        }
        return lowerCostPathFound;
    }

    public String getlowerPathQoS() {
        return lowerCostPathFound;
    }

    /*
     * Method: addRoutingTable
     */
    /*
     * Adds the Routing table to each one of the destination nodes
     */
    public void addRoutingTable(ArrayList<ArrayList<Integer>> routingTable) {
        routingTablesArray.add(routingTable);
    }

    /*
     * Method: addCostMatrix
     */
    /*
     * Adds cost's matrix (2D Array randomly generated or .txt file) to the
     * i_costMatrix in order to calculate fitness
     */
    public void addCostMatrix(int[][] costMatrix) {
        i_costMatrix = new int[costMatrix.length][costMatrix[0].length];
        for (int i = 0; i < costMatrix.length; i++) {
            for (int j = 0; j < costMatrix[i].length; j++) {
                i_costMatrix[i][j] = costMatrix[i][j];
            }
        }
    }

    /*
     * Method: addDelayMatrix
     */
    /*
     * Adds cost's matrix (2D Array randomly generated or .txt file) to the
     * i_costMatrix in order to calculate fitness
     */
    public void addDelayMatrix(int[][] delayMatrix) {
        i_delayMatrix = new int[delayMatrix.length][delayMatrix[0].length];
        for (int i = 0; i < delayMatrix.length; i++) {
            for (int j = 0; j < delayMatrix[i].length; j++) {
                i_delayMatrix[i][j] = delayMatrix[i][j];
            }
        }
    }

    /*
     * Method: generateChromosome
     */
    /*
     * Generates the initial chromosome pool (random route's index from the
     * routing tables)
     */
    public void generateChromosomes() {
        chromosomeLength = routingTablesArray.size();
        for (int k = 0; k < i_numberOfIndividuals; k++) {

            for (int i = 0; i < chromosomeLength; i++) {
                int routeLength = routingTablesArray.get(i).size();
                int randomRoute = (int) (Math.random() * (routeLength) + 1); // Generate a random number between 1 and the route length
                randomRoute = randomRoute - 1;
                population.add(randomRoute);
            }

        }

//        System.out.println("Chromosomes: ");
//        int k = 1;
//        for (int i = 0; i < population.size(); i++) {
//            if (i == (chromosomeLength * k)) {
//                System.out.println();
//                k++;
//            }
//            System.out.print(population.get(i) + " ");
//        }
    }


    /*
     * Method: calculateFitness
     */
    /*
     * Based on the cost matrix the method calculates the fitness (cost) of each
     * chromosome.
     */
    private void calculateFitness() {
        int genCounter = 0;
        for (int k = 0; k < i_numberOfIndividuals; k++) {
            double sum = 0;
            for (int i = 0; i < chromosomeLength; i++) {
                double fitness = 0;
                int counter = 0;
                int sourceNode = 0;
                int destinationNode = 0;
                int route = population.get(i + genCounter);
                String path = routingTablesArray.get(i).get(route).toString();
                //System.out.println(path);
                for (int j = 0; j < routingTablesArray.get(i).get(route).size(); j++) {
                    //System.out.println(routingTablesArray.get(i).get(route).get(j));
                    if (j % 2 == 0) {
                        sourceNode = routingTablesArray.get(i).get(route).get(j);
                        counter++;
                    }

                    if (j % 2 == 1) {
                        destinationNode = routingTablesArray.get(i).get(route).get(j);
                        counter++;
                    }

                    if (counter % 2 == 0) {
                        fitness += i_costMatrix[sourceNode][destinationNode];

                    }

                }
                fitnessGen.add(fitness);
            }
            genCounter = genCounter + chromosomeLength;

            for (int i = 0; i < fitnessGen.size(); i++) {
                sum += fitnessGen.get(i);
            }
            fitnessArray.add(sum);
            fitnessGen.clear();

        }


//        System.out.println();
//        System.out.println("Fitness");
//        for (int i = 0; i < i_numberOfIndividuals; i++) {
//            System.out.println(fitnessArray.get(i));
//        }
    }

    /*
     * Method: calculateAverageFitness
     */
    /*
     * Saves the average fitness found per generation in an ArrayList to use it
     * in the Plot class (generate the fitness graph)
     */
    private void calculateAverageFitness() {
        double sum = 0;
        for (int i = 0; i < fitnessArray.size(); i++) {
            sum += fitnessArray.get(i);
        }
        averageFitness.add(sum / (fitnessArray.size()));
    }

    /*
     * Method: calculateMinFitness
     */
    /*
     * Calculates the minimum fitness found in the generation and based on it
     * the method stores the lower cost path to the multicast nodes.
     */
    private void calculateMinFitness(int counter) {
        int position = 0;
        double lower = fitnessArray.get(0);
        for (int i = 0; i < fitnessArray.size(); i++) {
            if (fitnessArray.get(i) < lower) {
                lower = fitnessArray.get(i);
                position = i;
            }
        }
        minFitness.add(lower);
        lowerCostChromosome.add(new ArrayList<Integer>());
        lowerCostPath.add(new ArrayList<Integer>());
        for (int i = 0; i < chromosomeLength; i++) {
            lowerCostChromosome.get(counter).add(population.get((position * chromosomeLength) + i));
        }
        for (int i = 0; i < chromosomeLength; i++) {
            int pathNumber = lowerCostChromosome.get(counter).get(i);
            for (int j = 0; j < routingTablesArray.get(i).get(pathNumber).size(); j++) {
                lowerCostPath.get(counter).add(routingTablesArray.get(i).get(pathNumber).get(j));
            }
        }
    }

    private void orderPopulation() {
        //The whole population ordered according to the fitness. This allow to check QoS constrains the chromosomes        
        fitnessTmp.clear();
        orderedFitnessArrayQoS.clear();
        populationOrderedByFitness.clear();
        fitnessTmp.addAll(fitnessArray);// It’s necessary to create a new ArrayList because original will be changed (change to 0.0)
        for (int i = 0; i < i_numberOfIndividuals; i++) {
            double lower = fitnessTmp.get(0);
            int position = 0;
            for (int j = 0; j < fitnessTmp.size(); j++) {
                if (fitnessTmp.get(j) < lower) {
                    lower = fitnessTmp.get(j);
                    position = j;
                }
            }
            fitnessTmp.set(position, Double.POSITIVE_INFINITY);
            orderedFitnessArrayQoS.add(lower);
            populationOrderedByFitness.add(new ArrayList<Integer>());
            for (int j = 0; j < chromosomeLength; j++) {
                populationOrderedByFitness.get(i).add(population.get((position * chromosomeLength) + j));

            }

        }

    }

    /*
     * Method: doFittestSelection()
     */
    /*
     * Select 2 fittest parents (according to the Pn parameter) in order to
     * generate 2 sons and select the fittest among parents and offspring.
     */
    private void doFittestSelection() {
        int selected = i_numberOfSelectedParents;
        fitnessArraySelection.addAll(fitnessArray);// It’s necessary to create a new ArrayList because original will be changed (change to 0.0)

        for (int i = 0; i < selected; i++) {
            double lower = fitnessArraySelection.get(0);
            int position = 0;
            for (int j = 0; j < fitnessArraySelection.size(); j++) {
                if (fitnessArraySelection.get(j) < lower) {
                    lower = fitnessArraySelection.get(j);
                    position = j;
                }
            }
            fitnessArraySelection.set(position, Double.POSITIVE_INFINITY);
            orderedFitnessArray.add(lower);
            fittestparentsToCrossover.add(new ArrayList<Integer>());
            for (int j = 0; j < chromosomeLength; j++) {
                fittestparentsToCrossover.get(i).add(population.get((position * chromosomeLength) + j));

            }

        }

        for (int i = 0; i < i_numberOfIndividuals; i++) {
            parentsToCrossover.add(new ArrayList<Integer>());
            int parent1 = (int) (Math.random() * (fittestparentsToCrossover.size()) + 1); // Generate a random number between 1 and the number of parents

            parent1 = parent1 - 1;


            for (int j = 0; j < chromosomeLength; j++) {
                parentsToCrossover.get(i).add(fittestparentsToCrossover.get(parent1).get(j));
            }
            int parent2 = (int) (Math.random() * (fittestparentsToCrossover.size()) + 1);
            parent2 = parent2 - 1;

            for (int j = 0; j < chromosomeLength; j++) {
                parentsToCrossover.get(i).add(fittestparentsToCrossover.get(parent2).get(j));
            }
        }


//        System.out.println();
//        System.out.println("Parents: ");
//        for (int i = 0; i < parentsToCrossover.size(); i++) {
//            for (int j = 0; j < parentsToCrossover.get(i).size(); j++) {
//                System.out.print(parentsToCrossover.get(i).get(j) + " ");
//            }
//            System.out.println();
//        }
    }

    /*
     * Method: doRandomSelection
     */
    /*
     * Select randomly 2 parents (numberOfIndividuals times) in order to get
     * population_size offsprings.
     */
    private void doRandomSelection() {
        for (int i = 0; i < i_numberOfIndividuals; i++) {
            parentsToCrossover.add(new ArrayList<Integer>());
            int parent1 = (int) (Math.random() * (i_numberOfIndividuals) + 1); // Generate a random number between 1 and the number of individuals
            int parent2 = (int) (Math.random() * (i_numberOfIndividuals) + 1);
            parent1 = parent1 - 1;
            parent2 = parent2 - 1;

            for (int j = 0; j < chromosomeLength; j++) {
                parentsToCrossover.get(i).add(population.get((parent1 * chromosomeLength) + j));
            }

            for (int j = 0; j < chromosomeLength; j++) {
                parentsToCrossover.get(i).add(population.get((parent2 * chromosomeLength) + j));
            }
        }

//        System.out.println();
//        System.out.println("Parents: ");
//        for (int i = 0; i < parentsToCrossover.size(); i++) {
//            for (int j = 0; j < parentsToCrossover.get(i).size(); j++) {
//                System.out.print(parentsToCrossover.get(i).get(j) + " ");
//            }
//            System.out.println();
//        }
    }

    /*
     * Method : doCrossoverDestructive
     */
    /*
     * Performs the crossover genetic operator, it generates a random point for
     * crossing. A parent’s pair makes one son to completing the original
     * population size. It also performs the replacement for the next
     * generation, in this case the replacement strategy is destructive due to
     * the offspring replace the parents it doesn’t care if they have better
     * fitness.
     */
    private void doCrossoverDestructive() {

        for (int i = 0; i < i_numberOfIndividuals; i++) {

            int randomCrossover = (int) (Math.random() * (chromosomeLength) + 1); // Generate a random number between 0 and the number of genes
            randomCrossover = randomCrossover - 1;
            //System.out.println(randomCrossover);

            int crossoverContinue = chromosomeLength + randomCrossover;
            int counter = 0;

            for (int j = 0; j < randomCrossover; j++) {
                offsprings.add(parentsToCrossover.get(i).get(j));
            }

            for (int j = randomCrossover; j < chromosomeLength; j++) {
                offsprings.add(parentsToCrossover.get(i).get(crossoverContinue + counter));
                counter++;
            }
        }

//        System.out.println();
//        System.out.println("Offsprings: ");
//        int k = 1;
//        for (int i = 0; i < offsprings.size(); i++) {
//            if (i == (chromosomeLength * k)) {
//                System.out.println();
//                k++;
//            }
//            System.out.print(offsprings.get(i) + " ");
//        }
//        System.out.println();
    }

    /*
     * Method : doCrossoverFittest()
     */
    /*
     * Performs the crossover genetic operator, it generates a random point for
     * crossing. A parent’s pair makes two sons. It also performs the
     * replacement for the next generation, in this case the replacement
     * strategy is based on the fittest chromosome among the parents and
     * offspring.
     */
    private void doCrossoverFittest() {
        for (int i = 0; i < i_numberOfIndividuals; i++) {
            int randomCrossover = (int) (Math.random() * (chromosomeLength) + 1); // Generate a random number between 0 and the number of genes
            randomCrossover = randomCrossover - 1;
            //System.out.println(randomCrossover);
            int crossoverStart;

            //Crossover from first parent to second parent
            int crossoverContinue = chromosomeLength + randomCrossover;
            int counter = 0;
            for (int j = 0; j < randomCrossover; j++) {
                sons.add(parentsToCrossover.get(i).get(j));
            }

            for (int j = randomCrossover; j < chromosomeLength; j++) {
                sons.add(parentsToCrossover.get(i).get(crossoverContinue + counter));
                counter++;
            }

            //Crossover from second parent to first parent
            for (int j = 0; j < randomCrossover; j++) {
                sons.add(parentsToCrossover.get(i).get(j + chromosomeLength));
            }

            for (int j = randomCrossover; j < chromosomeLength; j++) {
                sons.add(parentsToCrossover.get(i).get(j));

            }

            sons.addAll(parentsToCrossover.get(i));

            //Calculate son's and parent's fitness
            double sumFitness = 0;
            int genCounter = 0;
            ArrayList<Double> sonsFitnessArray = new ArrayList<Double>();

            for (int l = 0; l < 4; l++) { // For because of the number of sons and parents

                for (int j = 0; j < chromosomeLength; j++) {
                    double fitness = 0;
                    int counter2 = 0;
                    int sourceNode = 0;
                    int destinationNode = 0;
                    int routeIndex = sons.get(j + genCounter);
                    String path = routingTablesArray.get(j).get(routeIndex).toString();
                    for (int k = 0; k < routingTablesArray.get(j).get(routeIndex).size(); k++) {
                        //System.out.println(routingTablesArray.get(i).get(route).get(j));
                        if (k % 2 == 0) {
                            sourceNode = routingTablesArray.get(j).get(routeIndex).get(k);
                            counter2++;
                        }

                        if (k % 2 == 1) {
                            destinationNode = routingTablesArray.get(j).get(routeIndex).get(k);
                            counter2++;
                        }

                        if (counter2 % 2 == 0) {
                            fitness += i_costMatrix[sourceNode][destinationNode];

                        }

                    }
                    sumFitness += fitness;

                }
                sonsFitnessArray.add(sumFitness);
                genCounter = genCounter + chromosomeLength;
                sumFitness = 0;

            }

            int position = 0;
            double lower = sonsFitnessArray.get(0);
            for (int k = 0; k < sonsFitnessArray.size(); k++) {
                if (sonsFitnessArray.get(k) < lower) {
                    lower = sonsFitnessArray.get(k);
                    position = k;
                }
            }
            for (int j = 0; j < chromosomeLength; j++) {
                offsprings.add(sons.get((chromosomeLength * position) + j));

            }
            sonsFitnessArray.clear();
            sons.clear();




        }

    }

    /*
     * Method : doMutation()
     */
    /*
     * Randomly changes genes based on the mutation probability and replace the
     * population for the next generation
     */
    private void doMutation() {

        double random;
        int counter = 0;
        int routeLength;

        for (int i = 0; i < offsprings.size(); i++) { //only the sons pass trough mutation
            random = Math.random();
            if (i_mutationRate > random) {
                routeLength = routingTablesArray.get(counter).size();
                int randomRoute = (int) (Math.random() * (routeLength) + 1); // Generate a random number between 1 and the route length
                randomRoute = randomRoute - 1;
                offsprings.set(i, randomRoute);
            }
            counter++;
            if (counter == chromosomeLength) {
                counter = 0;
            }
        }

//        System.out.println();
//        System.out.println("Offsprings after mutation: ");
//        int k = 1;
//        for (int i = 0; i < offsprings.size(); i++) {
//            if (i == (chromosomeLength * k)) {
//                System.out.println();
//                k++;
//            }
//            System.out.print(offsprings.get(i) + " ");
//        }
//        System.out.println();

        //Replace the population for the next generation
        population.clear();
        population.addAll(offsprings);
        fitnessArray.clear();
        offsprings.clear();
        parentsToCrossover.clear();
        fitnessArraySelection.clear();
        fittestparentsToCrossover.clear();


    }

    private boolean checkDemand(ArrayList<Integer> subroute) {
        double delay = 0;
        double delaymi = 0;
        double delaymj = 0;
        double jitter;
        double delaytmp = 0;
        double sum = 0;
        for (int i = 0; i < subroute.size(); i++) {
            int counter = 0;
            int sourceNode = 0;
            int destinationNode = 0;
            int route = subroute.get(i);
            String path = routingTablesArray.get(i).get(route).toString();
            //System.out.println(path);

            for (int j = 0; j < routingTablesArray.get(i).get(route).size(); j++) {
                if (j % 2 == 0) {
                    sourceNode = routingTablesArray.get(i).get(route).get(j);
                    counter++;
                }

                if (j % 2 == 1) {
                    destinationNode = routingTablesArray.get(i).get(route).get(j);
                    counter++;
                }

                if (counter % 2 == 0) {
                    delay += i_delayMatrix[sourceNode][destinationNode];
                    delaytmp += i_delayMatrix[sourceNode][destinationNode];
                }
            }


            if (i == 0) {
                delaymi = delaytmp;
            }
            if (i == 1) {
                delaymj = delaytmp;
            }
            delaytmp = 0;
        }
        jitter = delaymi - delaymj;
        if (jitter <= delayVariation && delay <= delayMulticast) {
            return true;
        } else {
            return false;
        }
    }

    private void getRouteFromChromosome(ArrayList<Integer> chromosome) {
        for (int i = 0; i < chromosome.size(); i++) {
            int route = chromosome.get(i);
            lowerPathQoS += routingTablesArray.get(i).get(route).toString() + " ";
        }
    }

    /*
     * Method : performGeneticRouting()
     */
    /*
     * General loop to performs then selected generations
     */
    public void performGeneticRouting() {
        for (int i = 0; i < i_numberOfGenerations; i++) {
            calculateFitness();
            calculateAverageFitness();
            calculateMinFitness(i);
            orderPopulation();
            //doRandomSelection();
            doFittestSelection();
            //doCrossoverDestructive();
            doCrossoverFittest();
            doMutation();
            try {
                if (i == i_numberOfGenerations - 1) {
                    boolean qos;
                    int counter = 0;
                    do {
                        qos = checkDemand(populationOrderedByFitness.get(counter));
                        counter++;
                    } while (qos == false);
                    getRouteFromChromosome(populationOrderedByFitness.get(counter - 1));
                }

            } catch (Exception e) {
                pathFound = false;
            }
        }
    }

    public void performGeneticRouting(boolean randomSelection, boolean crossoverDestructive) {
        for (int i = 0; i < i_numberOfGenerations; i++) {
            calculateFitness();
            calculateAverageFitness();
            calculateMinFitness(i);
            orderPopulation();
            if (randomSelection == true) {
                doRandomSelection();
            } else {
                doFittestSelection();
            }
            if (crossoverDestructive == true) {
                doCrossoverDestructive();
            } else {
                doCrossoverFittest();

            }
            doMutation();
            try {
                if (i == i_numberOfGenerations - 1) {
                    boolean qos;
                    int counter = 0;
                    do {
                        qos = checkDemand(populationOrderedByFitness.get(counter));
                        counter++;
                    } while (qos == false);
                    getRouteFromChromosome(populationOrderedByFitness.get(counter - 1));
                }

            } catch (Exception e) {
                pathFound = false;
            }


        }
    }

    public void PrintChromosome() {
        System.out.println("Chromosomes: ");
        int k = 1;
        for (int i = 0; i < population.size(); i++) {
            if (i == (chromosomeLength * k)) {
                System.out.println();
                k++;
            }
            System.out.print(population.get(i) + " ");
        }
    }

    public void printFitness() {
        System.out.println();
        System.out.println("Fitness");
        for (int i = 0; i < i_numberOfIndividuals; i++) {
            System.out.println(fitnessArray.get(i));
        }
    }

    public void printAverageFitness() {
        System.out.println();
        System.out.println("Average Fitness: ");
        for (int i = 0; i < averageFitness.size(); i++) {
            System.out.print(averageFitness.get(i) + "\t");
        }
    }

    public void printMinFitness() {
        //System.out.println();
        //System.out.println("Min Fitness: ");
        for (int i = 0; i < minFitness.size(); i++) {
            System.out.print(minFitness.get(i) + "\t");
        }
    }

    public void printLowerCostPath() {
        System.out.println();
        System.out.println("Lower Cost Path Found: ");
        //for (int i = 0; i < lowerCostPath.size(); i++) {
        //System.out.print(i + ". ");
        for (int j = 0; j < lowerCostPath.get(lowerCostPath.size() - 1).size(); j++) {
            System.out.print(lowerCostPath.get(lowerCostPath.size() - 1).get(j) + " ");
        }
        System.out.println();
        //}
    }

    public void printLowerCostPathQoS() {
        if (pathFound == true) {
            System.out.println();
            System.out.println("Lower Cost Path Found with QoS constrains: (Delay <= " + delayMulticast + " - Delay Variation <= " + delayVariation + ")");
            System.out.println(lowerPathQoS);
        } else {
            System.out.println("No path found with QoS constrains (Delay <= " + delayMulticast + " - Delay Variation <= " + delayVariation + ")");
        }


    }

    public void printParents() {
        System.out.println("Parents: ");
        for (int i = 0; i < parentsToCrossover.size(); i++) {
            for (int j = 0; j < parentsToCrossover.get(i).size(); j++) {
                System.out.print(parentsToCrossover.get(i).get(j) + " ");
            }
            System.out.println();
        }

    }

    public void printOffsprings() {
        System.out.println();
        System.out.println("Offsprings: ");
        int k = 1;
        for (int i = 0; i < offsprings.size(); i++) {
            if (i == (chromosomeLength * k)) {
                System.out.println();
                k++;
            }
            System.out.print(offsprings.get(i) + " ");
        }
        System.out.println();
    }

    public void printCostMatrix() {
        System.out.println();
        System.out.println("Cost Matrix for fitness: ");
        for (int i = 0; i < i_costMatrix.length; i++) {
            for (int j = 0; j < i_costMatrix[i].length; j++) {
                System.out.print(i_costMatrix[i][j] + " ");
            }
            System.out.println();
        }
    }

    public void PrintRoutingTables() {
        for (int i = 0; i < routingTablesArray.size(); i++) {
            System.out.println("Routing Table " + i + " :");
            for (int j = 0; j < routingTablesArray.get(i).size(); j++) {
                for (int j2 = 0; j2 < routingTablesArray.get(i).get(j).size(); j2++) {
                    System.out.print(routingTablesArray.get(i).get(j).get(j2) + " ");
                }
                System.out.println();
            }
        }
    }
    //instance variables
    private ArrayList<ArrayList<ArrayList<Integer>>> routingTablesArray = new ArrayList<ArrayList<ArrayList<Integer>>>();
    private ArrayList<ArrayList<Integer>> parentsToCrossover = new ArrayList<ArrayList<Integer>>();
    private ArrayList<ArrayList<Integer>> fittestparentsToCrossover = new ArrayList<ArrayList<Integer>>();
    private ArrayList<ArrayList<Integer>> populationOrderedByFitness = new ArrayList<ArrayList<Integer>>();
    private ArrayList<ArrayList<Integer>> lowerCostPath = new ArrayList<ArrayList<Integer>>();
    private ArrayList<Integer> lowerCostPathQoS = new ArrayList<Integer>();
    private ArrayList<ArrayList<Integer>> lowerCostChromosome = new ArrayList<ArrayList<Integer>>();
    private ArrayList<Integer> population = new ArrayList<Integer>();
    private ArrayList<Double> fitnessArray = new ArrayList<Double>();
    private ArrayList<Double> fitnessArraySelection = new ArrayList<Double>();
    private ArrayList<Double> fitnessTmp = new ArrayList<Double>();
    private ArrayList<Double> orderedFitnessArray = new ArrayList<Double>();
    private ArrayList<Double> orderedFitnessArrayQoS = new ArrayList<Double>();
    private ArrayList<Double> fitnessGen = new ArrayList<Double>();
    private ArrayList<Integer> offsprings = new ArrayList<Integer>();
    private ArrayList<Integer> sons = new ArrayList<Integer>();
    private ArrayList<Double> averageFitness = new ArrayList<Double>();
    private ArrayList<Double> minFitness = new ArrayList<Double>();
    private int i_numberOfIndividuals;
    private double i_mutationRate;
    private int i_numberOfGenerations;
    private int chromosomeLength;
    private int[][] i_costMatrix;
    private int[][] i_delayMatrix;
    private int i_numberOfSelectedParents = 15;
    private String lowerCostPathFound = "";
    private double delayMulticast = 30;
    private double delayVariation = 20;
    private ArrayList<Integer> subroute;
    private String lowerPathQoS = "";
    private boolean pathFound = true;
}
